<template>
  <div
    class="editor-container"
    :style="{
      width: `${basicPropsValue.width}px`,
      height: `${basicPropsValue.height}px`
    }"
  >
    <canvas
      class="myCanvas"
      :style="{ backgroundSize: `${extendedPropsValue.gridWidth}px ${extendedPropsValue.gridHeight}px`}"
      :width="basicPropsValue.width"
      :height="basicPropsValue.height"
      ref="refCanvas"
      @mousedown="onPressdownCanvas"
      @touchstart="onPressdownCanvas"
      @mousemove="onPressmoveCanvas"
      @touchmove="onPressmoveCanvas"
      @mouseup="onPressupCanvas"
      @touchend="onPressupCanvas"
      @mouseleave="onPressupCanvas"
      @touchleave="onPressupCanvas"
    ></canvas>
    <div class="tools">
      <a-button class="clear-btn" type="danger" @click="onClearPreset">清除</a-button>
      <a-tooltip placement="bottomLeft">
        <template #title>
          <span>预设有两种模式, 默认是设置多边形，打开开关，调整为设置圆形，第一次点击确定圆心，第二次点击是确定半径</span>
        </template>
        <a-switch v-model:checked="editingPreset.isDrawCircle" checked-children="圆" un-checked-children="圆" />
      </a-tooltip>
      <a-tooltip placement="bottomLeft">
        <template #title>
          <span>是否展示圆形</span>
        </template>
        <a-switch class="is-show-circle" v-model:checked="editingPreset.isShowCircle" checked-children="圆心" un-checked-children="圆心" />
      </a-tooltip>
      
    </div>
    <div
      class="click-indicator"
      :style="{
        display: isClickIndicatorVisible ? 'block' : 'none',
        top: `${clickedPosition.y}px`,
        left: `${clickedPosition.x}px`
      }"
    ></div>
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType, onMounted, ref, watch, reactive } from 'vue';
import find from 'lodash.find';
import debounce from 'lodash.debounce';

interface IPolygon {
  points: [number, number][],
  isDrawCircle: boolean,
  isShowCircle: boolean,
  
}

export default defineComponent({
  props: {
    basicPropsValue: {
      type: Object as PropType<{ width: number, height: number }>,
      default: () => ({ width: 900, height: 600 })
    },
    extendedPropsValue: {
      type: Object as PropType<{ gridWidth: number, gridHeight: number }>,
      default: () => ({ gridWidth: 40, gridHeight: 40 })
    },
    preset: { type: Object as PropType<IPolygon | null>, default: () => null },
    onValueUpdated: { type: Function as PropType<(v: IPolygon[]) => void> }
  },
  setup(props) {
    const editingPreset = ref({} as IPolygon );
    const refCanvas = ref(null as null | HTMLCanvasElement);
    const clickedPosition = reactive({ x: 0, y: 0 });
    const isClickIndicatorVisible = ref(false);
    const debouncedHideClickIndicator = debounce(() => { isClickIndicatorVisible.value = false; }, 1000);

    // @ts-ignore
    window.preset = editingPreset;

    onMounted(() => {
      if (props.preset) {
        editingPreset.value = JSON.parse(JSON.stringify(props.preset));
      } else {
        editingPreset.value = { points: [] ,isDrawCircle: false,isShowCircle:false };
      }
      renderCanvas();
    });

    watch(editingPreset, () => {
      if (props.onValueUpdated) {
        props.onValueUpdated(JSON.parse(JSON.stringify(editingPreset.value)));
      }
    }, { deep: true });


    function findPointAtPos(pos) {
      const tolerance = 10;
      if (!editingPreset.value) return null;
      for (let i = editingPreset.value.points.length - 1; i >= 0; i--) {
        const point = editingPreset.value.points[i];
        if (Math.abs(point[0] - pos[0]) < tolerance && Math.abs(point[1] - pos[1]) < tolerance) {
          return { pointIndex: i };
        }
      }
      return null;
    }

    let canvasRect: DOMRect | null = null;
    let mousedownPoint: { pointIndex: number } | null = null;
    let mousePos: [number, number] | null = null;
    let isMousedownTriggered = false;
    function onPressdownCanvas(evt) {
      if (!refCanvas.value) return;
      if (!canvasRect) {
        canvasRect = refCanvas.value.getBoundingClientRect();
      }
      const clientX = evt.type === 'touchstart' ? evt.touches[0].clientX : evt.clientX;
      const clientY = evt.type === 'touchstart' ? evt.touches[0].clientY : evt.clientY;
      const pos: [number, number] = [clientX - canvasRect.left, clientY - canvasRect.top];
      mousePos = pos;
      mousedownPoint = findPointAtPos(pos);
      isMousedownTriggered = true;
    }
    function onPressmoveCanvas(evt) {
      if (!canvasRect || !editingPreset.value) return;
      const clientX = evt.type === 'touchmove' ? evt.touches[0].clientX : evt.clientX;
      const clientY = evt.type === 'touchmove' ? evt.touches[0].clientY : evt.clientY;
      const pos: [number, number] = [clientX - canvasRect.left, clientY - canvasRect.top];
      if (mousedownPoint) {
        const { pointIndex } = mousedownPoint;
        const point = editingPreset.value.points[pointIndex];
        if (point && mousePos) {
          point[0] += pos[0] - mousePos[0];
          point[1] += pos[1] - mousePos[1];
          renderCanvas();
        }
      }
      mousePos = pos;
    }
    function onPressupCanvas(evt) {
      console.log(evt.type);
      if (!mousedownPoint && isMousedownTriggered) {
        if (refCanvas.value && mousePos) {
          const x = Math.round(mousePos[0] / props.extendedPropsValue.gridWidth) * props.extendedPropsValue.gridWidth;
          const y = Math.round(mousePos[1] / props.extendedPropsValue.gridHeight) * props.extendedPropsValue.gridHeight;
          if (!editingPreset.value) {
            editingPreset.value = { points: [] ,isDrawCircle: false,isShowCircle:false };
          }
          const existingPoint = find(editingPreset.value.points, (point) => Math.abs(x - point[0]) < 1 && Math.abs(y - point[1]) < 1);
          if (!existingPoint) {
            if(editingPreset.value.isDrawCircle) {
              if(editingPreset.value.points.length <2) {
                editingPreset.value.points.push([x, y]);
                renderCanvas();
              }
            }else {
              editingPreset.value.points.push([x, y]);
              renderCanvas();
            }
          
          }
          clickedPosition.x = x;
          clickedPosition.y = y;
          isClickIndicatorVisible.value = true;
          debouncedHideClickIndicator();
        }
      }
      mousedownPoint = null;
      mousePos = null;
      isMousedownTriggered = false;
    }

    function renderCanvas() {
      console.log(JSON.stringify(editingPreset.value));
      if (!refCanvas.value) return;
      refCanvas.value.width = refCanvas.value.width;
      if (!editingPreset.value || editingPreset.value.points.length < 2) return;
      const ctx = refCanvas.value.getContext('2d')
      if (!ctx) return;
      if(editingPreset.value.isDrawCircle && editingPreset.value.points.length == 2) {
        console.log("draw circle");
         const riadius = Math.sqrt(Math.pow((editingPreset.value.points[1][0] - editingPreset.value.points[0][0]), 2) + Math.pow((editingPreset.value.points[1][1] - editingPreset.value.points[0][1]), 2));
        
        ctx.beginPath();
        ctx.arc(editingPreset.value.points[0][0] , editingPreset.value.points[0][1], riadius,0, 2 * Math.PI ,false)
        ctx.lineWidth = 2; // 边框宽度
        ctx.strokeStyle = '#003300'; // 边框颜色
        ctx.stroke();
        ctx.closePath()
        const pointRaidus = 10;
        ctx.lineWidth = 2;
        ctx.strokeStyle = '#ff2a51';
        ctx.fillStyle = '#007936';
        for (let i = 0; i < editingPreset.value.points.length; i++) {
        const point = editingPreset.value.points[i];
        ctx.beginPath();
        ctx.ellipse(point[0], point[1], pointRaidus, pointRaidus, 0, 0, 2 * Math.PI);
        ctx.fill();
        ctx.stroke();
      }
      }else {
      ctx.lineWidth = 2;
      ctx.strokeStyle = '#000';
      ctx.beginPath();
      ctx.moveTo(editingPreset.value.points[0][0], editingPreset.value.points[0][1]);
      for (let i = 1; i < editingPreset.value.points.length; i++) {
        const point = editingPreset.value.points[i];
        ctx.lineTo(point[0], point[1]);
      }
      ctx.closePath();
      ctx.stroke();
      const pointRaidus = 10;
      ctx.lineWidth = 2;
      ctx.strokeStyle = '#ff2a51';
      ctx.fillStyle = '#007936';

      for (let i = 0; i < editingPreset.value.points.length; i++) {
        const point = editingPreset.value.points[i];
        ctx.beginPath();
        ctx.ellipse(point[0], point[1], pointRaidus, pointRaidus, 0, 0, 2 * Math.PI);
        ctx.fill();
        ctx.stroke();
      }
      }
    }

    function onClearPreset() {
      editingPreset.value = { points: [] ,isDrawCircle: false,isShowCircle:false };
      renderCanvas();
    }
  
    
    return {
      editingPreset,
      refCanvas,
      isClickIndicatorVisible,
      clickedPosition,
      onClearPreset,
      onPressdownCanvas,
      onPressmoveCanvas,
      onPressupCanvas,
     
    };
  }
})
</script>

<style lang="less" scoped>
.editor-container {
  position: absolute;
  top: 20px;
  left: 20px;
  box-shadow: 0 0 20px 2px gray;
  .myCanvas {
    width: 100%;
    height: 100%;
    background-image: linear-gradient(0deg, #eee 1px, transparent 1px), linear-gradient(90deg, #eee 1px, transparent 1px);
    background-repeat: repeat;
  }
  .tools {
    position: absolute;
    bottom: 10px;
    left: 10px;
    .clear-btn {
      margin-right: 10px;
    }
    .is-show-circle {
      margin-left: 10px;
    }
  }

  .click-indicator {
    position: absolute;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    background-color: #52cbfc;
  }
}
</style>